#include "Reactor.hpp"
#include "Connection.hpp"
#include "Listener.hpp"
#include "Equeue.hpp"
#include "Recepter.hpp"
#include "ThreadPool.hpp"
#include "Http.hpp"
#include <sys/eventfd.h>

using namespace MyThreadPool;
using namespace Equeue;
const int DefaultThreadNum = 5;

using func_t = std::function<void()>;

int main(int argc, char *argv[])
{
    if (argc != 2 && argc != 3)
    {
        std::cout << "Usage: " << argv[0] << " port" << "(and ThreadNum)" << std::endl;
        exit(USAGE_ERROR);
    }

    uint16_t port = std::stoi(argv[1]);
    int ThreadNum = DefaultThreadNum;

    if (argc == 3)
    {
        ThreadNum = std::stoi(argv[2]);
    }

    if (ThreadNum <= 0)
    {
        std::cout << "error, it should be: ThreadNum >= 1" << std::endl;
        // exit(USAGE_ERROR);
        ThreadNum = DefaultThreadNum;
    }

    // Enable_File_Log_Strategy();
    Enable_Console_Log_Strategy();
    srand((unsigned int)time(NULL));

    // 主线程只负责监听网络套接字
    std::shared_ptr<Connection> Con = std::make_shared<Listener>(port);

    Con->RegisterEqueue([](std::vector<std::pair<int, InetAddr>> *eqevent) -> void
                        { event_queue::GetInStance()->Enqueue(eqevent); });

    std::unique_ptr<Reactor> rser = std::make_unique<Reactor>();

    rser->AddConnection(Con);

    // 将业务读取交给线程池处理
    for (int i = 1; i <= ThreadNum; i++)
    {

        ThreadPool<func_t>::GetInstance(ThreadNum)->Enqueue([&rser]()
        {
            std::shared_ptr<Http> http;

            int efd = eventfd(0,EFD_NONBLOCK | EFD_CLOEXEC | EFD_SEMAPHORE);
            if(efd<0)
            {
                LOG(Loglevel::ERROR)<<"eventfd error...";
            }
            
            //efd交给主线程管理
            rser->AddEfd(efd);
            std::shared_ptr<Connection> conn = std::make_shared<Recepter>(efd);

            conn->RegisterEqueue([](std::vector<std::pair<int,InetAddr>>* sockfds){
                event_queue::GetInStance()->PopAll(sockfds);
            });

            //业务处理回调函数
            conn->RegisterHandler([&http](std::string& inbuffer)->std::string
            {
                std::string ret_buffer;
                while(true)
                {
                    std::string packag;
                    if(!http->HttpHandlerRequest(inbuffer,packag))
                        break;
                    ret_buffer += packag;
                }
                return ret_buffer;
            });

            std::unique_ptr<Reactor> ser = std::make_unique<Reactor>(true);

            ser->AddConnection(conn);
            ser->Loop(); 
        });
    }

    rser->Loop();

    return 0;
}